<?php
namespace Commons;

use Firebase\JWT\JWT as JwtCore;

class Jwt
{
    private $keyCacheExpire = 30 * 24 * 60 * 60;

    private $signKey = 'wewechat';

    /**
     * 加密成jwt
     *
     * @param      $payload
     * @param bool $secret
     *
     * @return string
     * @throws \Exception
     */
    public function encode($payload, $secret = false)
    {
        if ($secret) {
            openssl_public_encrypt(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK), $encrypt, $this->getPublicKey());
            unset($payload);
            $payload['jwts'] = base64_encode($encrypt);
        }
        return JwtCore::encode($payload, $this->getPrivateKey(), 'RS256');
    }

    /**
     * 解析jwt
     *
     * @param $jwt
     *
     * @return mixed|object
     * @throws \Exception
     */
    public function decode($jwt)
    {
        $decode = JwtCore::decode($jwt, $this->getPublicKey(), ['RS256']);
        if (isset($decode->jwts)) {
            openssl_private_decrypt(base64_decode($decode->jwts), $decrypted, $this->getPrivateKey());
            return json_decode($decrypted);
        }
        return $decode;
    }

    /**
     * 获取密钥
     * @return bool|resource
     * @throws \Exception
     */
    private function getPrivateKey()
    {
        $path = App::globalConfig()->jwt->private_key;
        $mkey = md5(__METHOD__ . ENVIRONMENT . $path);
        try {
            $key = App::redis()->get($mkey);
            if (empty($key)) {
                $key = file_get_contents($path);
                App::redis()->save($mkey, $key, $this->keyCacheExpire);
            }
        } catch (\Exception $ex) {
            App::Logger()->error($ex->getMessage());
            $key = file_get_contents($path);
        }
        return openssl_get_privatekey($key);
    }

    /**
     * 获取公钥
     * @return resource
     * @throws \Exception
     */
    private function getPublicKey()
    {
        $path = App::globalConfig()->jwt->public_key;
        $mkey = md5(__METHOD__ . ENVIRONMENT . $path);
        try {
            $key = App::redis()->get($mkey);
            if (empty($key)) {
                $key = file_get_contents($path);
                App::redis()->save($mkey, $key, $this->keyCacheExpire);
            }
        } catch (\Exception $ex) {
            App::Logger()->error($ex->getMessage());
            $key = file_get_contents($path);
        }
        return openssl_pkey_get_public($key);
    }

    /**
     * jwt加入refresh_token
     *
     * @param array $data
     *
     * @return string
     */
    public function sign($data)
    {
        $mKey  = md5(ENVIRONMENT . $this->signKey);
        $sign  = [
            'key'       => $mKey,
            'expire_in' => 30 * 24 * 60 * 60,
            'create_at' => time()
        ];
        $crypt = new MyCrypt();
        return base64_encode($crypt->encrypt(json_encode(array_merge($sign, $data), JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK)));
    }

    /**
     * 解析refresh_token
     *
     * @param $sign
     *
     * @return mixed
     */
    public function verify($sign)
    {
        $crypt = new MyCrypt();
        return json_decode($crypt->decrypt(base64_decode($sign)), true);
    }

}
